#include "stdafx.h"
#include "MarchingCubeTable.h"
#include <iostream>

MarchingCubeTable* MarchingCubeTable::mct = 0;

//Initialize the mapTable
//int MarchingCubeTable::mapTable[15][12] = {
//{0,0,0,0,0,0,0,0,0,0,0,0},
//{192,144,132,0,0,0,0,0,0,0,0,0},
//{144,132,72,72,144,96,0,0,0,0,0,0},
//{192,144,132,72,12,9,0,0,0,0,0,0},
//{192,144,132,33,9,3,0,0,0,0,0,0},
// {192,144,72,144,72,18,72,18,33,0,0,0},
//{144,132,72,72,144,96,33,9,3,0,0,0},
//{192,96,72,132,12,6,33,9,3,0,0,0},
//{132,72,33,132,33,18,0,0,0,0,0,0},
//{132,6,3,132,3,192,192,3,33,33,192,96},
//{192,144,12,144,12,6,96,48,9,48,9,3},
//{192,132,18,192,18,9,18,9,3,192,96,9},
//{132,12,6,192,144,72,144,72,18,72,18,33},
//{192,144,132,72,12,9,18,6,3,96,48,33},
//{192,144,6,192,6,33,192,33,72,6,33,3}
//};
//
//int MarchingCubeTable::rotate[48][8] = {
//	{2,3,0,1,6,7,4,5},
//	{2,1,0,3,4,7,6,5},
//	{6,3,0,5,2,7,4,1},
//	{1,2,3,0,7,4,5,6},
//	{3,2,1,0,7,6,5,4},
//	{5,6,3,0,7,4,1,2},
//	{4,5,0,1,6,7,2,3},
//	{4,1,0,5,2,7,6,3},
//	{6,5,0,3,4,7,2,1},
//	{1,4,5,0,7,2,3,6},
//	{5,4,1,0,7,6,3,2},
//	{3,6,5,0,7,2,1,4},
//
//	{0,1,4,5,2,3,6,7},
//	{0,1,2,3,4,5,6,7},
//	{0,5,6,3,4,1,2,7},
//	{0,3,6,5,2,1,4,7},
//	{0,5,4,1,6,3,2,7},
//	{0,3,2,1,6,5,4,7},
//	{1,0,5,4,3,2,7,6},
//	{1,0,3,2,5,4,7,6},
//	{5,0,1,4,3,6,7,2},
//	{3,0,1,2,5,6,7,4},
//	{3,0,5,6,1,2,7,4},
//	{5,0,3,6,1,4,7,2},
//
//	{5,4,7,6,1,0,3,2},
//	{3,2,7,6,1,0,5,4},
//	{1,2,7,4,3,0,5,6},
//	{1,4,7,2,5,0,3,6},
//	{5,6,7,4,3,0,1,2},
//	{3,6,7,2,5,0,1,4},
//	{4,5,6,7,0,1,2,3},
//	{2,3,6,7,0,1,4,5},
//	{6,5,4,7,0,3,2,1},
//	{6,3,2,7,0,5,4,1},
//	{2,1,4,7,0,3,6,5},
//	{4,1,2,7,0,5,6,3},
//
//	{4,7,6,5,2,1,0,3},
//	{2,7,6,3,4,1,0,5},
//	{2,7,4,1,6,3,0,5},
//	{4,7,2,1,6,5,0,3},
//	{6,7,4,5,2,3,0,1},
//	{6,7,2,3,4,5,0,1},
//	{7,6,5,4,3,2,1,0},
//	{7,6,3,2,5,4,1,0},
//	{7,4,5,6,1,2,3,0},
//	{7,2,3,6,1,4,5,0},
//	{7,2,1,4,3,6,5,0},
//	{7,4,1,2,5,6,3,0}
//};

MarchingCubeTable::MarchingCubeTable(void)
{
	//initTMap();
	//initRotate();
	//cout<<"Test bitset array now:"<<triangles[0]<<endl;
	//cout<<"Triangles 1 is: "<<triangles[1]<<endl;
	//cout<<"Triangles 2 is: "<<triangles[2]<<endl;
}

MarchingCubeTable::~MarchingCubeTable(void)
{
}

//void MarchingCubeTable::initTMap(void)
//{
//	//Set the map of marching cube table
//	/*Vertices of the cube are indexed as follows:
//	
//	      6-----7
//	    / |      /|         y 
//	  /   |    /  |         |
//	 5---+--4   |         |
//	 |    3--+---2        +-----x
//	 |   /    |   /        /
//	 | /      | /        /
//	 0------1        z
//	
//	
//	*/
//
//	//case:0
//	//key= 1111 1111B
//	int key = 255;
//	//int value[12]={0,0,0,0,0,0,0,0,0,0,0,0};
//	tmap[key] = mapTable[0];
//	tmap.insert(make_pair(key, mapTable[0]));
//
//	//case:1
//	//key= 1000 0000B
//	//value = 192(11000000),144(10010000),132(10000100)
//	key = 128;
//	//int value1[12] = {192,144,132,0,0,0,0,0,0,0,0,0};
//	tmap[key] = mapTable[1];
//	tmap.insert(make_pair(key, mapTable[1]));
//
//	//case:2
//	//key= 1100 0000B
//	//value = 144(10010000),132(10000100),72(01001000),72(01001000),144(10010000),96(01100000)
//	key = 192;
//	//int value2[12] = {144,132,72,72,144,96,0,0,0,0,0,0};
//	tmap[key] = mapTable[2];
//	tmap.insert(make_pair(key, mapTable[2]));
//
//	//case:3
//	//key= 1000 1000B
//	//value = 192(11000000),144(10010000),132(10000100),72(01001000),12(00001100),9(00001001)
//	key = 136;
//	// int value3[12] = {192,144,132,72,12,9,0,0,0,0,0,0};
//	tmap[key] = mapTable[3];
//	tmap.insert(make_pair(key, mapTable[3]));
//
//	//case:4
//	//key= 1000 0001B
//	//value = 192(11000000),144(10010000),132(10000100),33(00100001),9(00001001),3(00000011)
//	key = 129;
//	tmap[key] = mapTable[4];
//	tmap.insert(make_pair(key, mapTable[4]));
//
//	//case:5
//	//key= 1000 1111B
//	//value = 192(11000000),144(10010000),72(01001000),144(10010000),72(01001000),18(00010010),72(01001000),18(00010010),33(00100001)
//	key = 143;
//	tmap[key] = mapTable[5];
//	tmap.insert(make_pair(key, mapTable[5]));
//
//	//case:6
//	//key= 1100 0001B
//	//value = 144(10010000),132(10000100),72(01001000),72(01001000),144(10010000),96(01100000),33(00100001),9(00001001),3(00000011)
//	key = 193;
//	tmap[key] = mapTable[6];
//	tmap.insert(make_pair(key, mapTable[6]));
//
//	//case:7
//	//key= 1011 1010B
//	//value = 192(11000000),96(01100000),72(01001000),132(10000100),12(00001100),6(00000110),33(00100001),9(00001001),3(00000011)
//	key = 186;
//	tmap[key] = mapTable[7];
//	tmap.insert(make_pair(key, mapTable[7]));
//
//	//case:8
//	//key= 1111 0000B
//	//value = 132(10000100),72(01001000),33(00100001),132(10000100),33(00100001),18(00010010)
//	key = 240;
//	tmap[key] = mapTable[8];
//	tmap.insert(make_pair(key, mapTable[8]));
//
//	//case:9
//	//key= 1011 0010B
//	//value = 132(10000100),6(00000110),3(00000011),132(10000100),3(00000011),192(11000000),192(11000000),3(00000011),33(00100001),33(00100001),192(11000000),96(01100000)
//	key = 178;
//	tmap[key] = mapTable[9];
//	tmap.insert(make_pair(key, mapTable[9]));
//
//	//case:10
//	//key= 1010 0101B
//	//value = 192(11000000),144(10010000),12(00001100),144(10010000),12(00001100),6(00000110),96(01100000),48(00110000),9(00001001),48(00110000),9(00001001),3(00000011)
//	key = 165;
//	tmap[key] = mapTable[10];
//	tmap.insert(make_pair(key, mapTable[10]));
//
//	//case:11
//	//key= 1011 0001B
//	//value = 192(11000000),132(10000100),18(00010010),192(11000000),18(00010010),9(00001001),18(00010010),9(00001001),3(00000011),192(11000000),96(01100000),9(00001001)
//	key = 177;
//	tmap[key] = mapTable[11];
//	tmap.insert(make_pair(key, mapTable[11]));
//
//	//case:12
//	//key= 1000 1011B
//	//value = 132(10000100),12(00001100),6(00000110),192(11000000),144(10010000),72(01001000),144(10010000),72(01001000),18(00010010),72(01001000),18(00010010),33(00100001)
//	key = 139;
//	tmap[key] = mapTable[12];
//	tmap.insert(make_pair(key, mapTable[12]));;
//
//	//case:13
//	//key= 1010 1010B
//	//value = 192(11000000),144(10010000),132(10000100),72(01001000),12(00001100),9(00001001),18(00010010),6(00000110),3(00000011),96(01100000),48(00110000),33(00100001)
//	key = 170;
//	tmap[key] = mapTable[13];
//	tmap.insert(make_pair(key, mapTable[13]));
//
//	//case:14
//	//key= 1000 1101B
//	//value = 192(11000000),144(10010000),6(00000110),192(11000000),6(00000110),33(00100001),192(11000000),33(00100001),72(01001000),6(00000110),33(00100001),3(00000011)
//	key = 141;
//	tmap[key] = mapTable[14];
//	tmap.insert(make_pair(key, mapTable[14]));
//
//}
//
//void MarchingCubeTable::initRotate(void)
//{
//	//Set the array of rotation
//	/*Vertices of the cube are indexed as follows:
//	
//	      6-----7
//	    / |      /|         y 
//	  /   |    /  |         |
//	 5---+--4   |         |
//	 |    3--+---2        +-----x
//	 |   /    |   /        /
//	 | /      | /        /
//	 0------1        z
//	
//	
//	rotate = { {3, 0, 1, 2, 5, 6, 7, 4},
//				   {2, 3, 0, 1, 6, 7, 4, 5},
//	            {1, 2, 3, 0, 7, 4, 5, 6},
//	            {6, 5, 4, 7, 0, 3, 2, 1},
//	            {5, 4, 7, 6, 1, 0, 3, 2},
//	            {4, 7, 6, 5, 2, 1, 0, 3},
//	            {7, 6, 5, 4, 3, 2, 1, 0} };*/
//	//rotate[0]: rotate 90 degree, look from 1
//	/*rotate[0][0] = 3;
//	rotate[0][1] = 0;
//	rotate[0][2] = 1;
//	rotate[0][3] = 2;
//	rotate[0][4] = 5;
//	rotate[0][5] = 6;
//	rotate[0][6] = 7;
//	rotate[0][7] = 4;
//
//	//rotate[1]: rotate 180 degree, look from 2
//	rotate[1][0] = 2;
//	rotate[1][1] = 3;
//	rotate[1][2] = 0;
//	rotate[1][3] = 1;
//	rotate[1][4] = 6;
//	rotate[1][5] = 7;
//	rotate[1][6] = 4;
//	rotate[1][7] = 5;	
//
//	//rotate[2]: rotate 270 degree, look from 3
//	rotate[2][0] = 1;
//	rotate[2][1] = 2;
//	rotate[2][2] = 3;
//	rotate[2][3] = 0;
//	rotate[2][4] = 7;
//	rotate[2][5] = 4;
//	rotate[2][6] = 5;
//	rotate[2][7] = 6;	
//
//	//rotate[3]: look from 4
//	rotate[3][0] = 6;
//	rotate[3][1] = 5;
//	rotate[3][2] = 4;
//	rotate[3][3] = 7;
//	rotate[3][4] = 0;
//	rotate[3][5] = 3;
//	rotate[3][6] = 2;
//	rotate[3][7] = 1;	
//
//	//rotate[4]: look from 5
//	rotate[4][0] = 5;
//	rotate[4][1] = 4;
//	rotate[4][2] = 7;
//	rotate[4][3] = 6;
//	rotate[4][4] = 1;
//	rotate[4][5] = 0;
//	rotate[4][6] = 3;
//	rotate[4][7] = 2;	
//
//	//rotate[5]: look from 6
//	rotate[5][0] = 4;
//	rotate[5][1] = 7;
//	rotate[5][2] = 6;
//	rotate[5][3] = 5;
//	rotate[5][4] = 2;
//	rotate[5][5] = 1;
//	rotate[5][6] = 0;
//	rotate[5][7] = 3;
//
//	//rotate[6]: look from 7
//	rotate[6][0] = 7;
//	rotate[6][1] = 6;
//	rotate[6][2] = 5;
//	rotate[6][3] = 4;
//	rotate[6][4] = 3;
//	rotate[6][5] = 2;
//	rotate[6][6] = 1;
//	rotate[6][7] = 0;*/
//	//case0: 
//	/*rotate[0][0] = 0;
//	rotate[0][1] = 1;
//	rotate[0][2] = 2;
//	rotate[0][3] = 3;
//	rotate[0][4] = 4;
//	rotate[0][5] = 5;
//	rotate[0][6] = 6;
//	rotate[0][7] = 7;*/
//}

MarchingCubeTable* MarchingCubeTable::getInstance()
{
	if(mct == 0)
	{
		mct = new MarchingCubeTable();
	}
	return mct;
}

/*bitset<8>* MarchingCubeTable::getTriangles(bitset<8> input)
{
	//Match the current input bitset with the marching cube table
	//if there are not any match cases, rotate the input bitset with 
	//    the rotate table, and match again
	//There must be one case matched
	bool t;
	int t_key;
	int *t_value;
	bitset<8> t_input;
	
	//Step1: Flip the bitset if the first element of the bitset is 0
	t = input.test(7);
	if(!t)
	{
		input.flip();
	}
	//Step2: Try to match the current bitset with the marching cube table
	t_key = (int)input.to_ulong();
	//cout<<"key is "<<t_key<<endl;
	if(tmap.find(t_key) != tmap.end())
	{
		//Find the matching cases and return the triangles sequence
		t_value = tmap[t_key];
		for(int i=0; i<12; i++)
		{
			bitset<8> temp(t_value[i]);
			//cout<<"temp is "<<temp<<endl;
			triangles[i] = temp;
		}
	//////////////////////////////test//////////////////////////
		for(int i=0; i<12; i++)
		{
			//cout<<"triangles bitset is: "<<triangles[i]<<endl;
		}
		return triangles;
	}

	for(int i=0; i<48; i++)
	{
		//rotate at most 7 times to match the marching cube table
		//Step3: Rotate the input bitset if there are not any match cases
		t_input = rot(input, rotate[i]);
		//cout<<"t_input is "<<t_input<<endl;
		//Step1: Flip the bitset if the first element of the bitset is 0
		t = t_input.test(7);
		if(!t)
		{
			t_input.flip();
		}
		//Step2: Try to match the current bitset with the marching cube table
		t_key = (int)t_input.to_ulong();
		if(tmap.find(t_key) != tmap.end())
		{
			//Find the matching cases and return the triangles sequence
			//Must rotate back the sequence
			t_value = tmap[t_key];
			for(int j=0; j<12; j++)
			{
				bitset<8> temp(t_value[j]);
				//cout<<"t_value is"<<t_value[j]<<endl;
						//cout<<"temp is "<<temp<<endl;
				if(t_value[j] != 0)
				{
					//Rotate the triangles sequence back
					temp = revert(temp, rotate[i]);
				}
							//cout<<"temp is "<<temp<<endl;
				triangles[j] = temp;
			}
			break;
		}		
	}
	//////////////////////////////test//////////////////////////
	for(int i=0; i<12; i++)
	{
		//cout<<"triangles bitset is: "<<triangles[i]<<endl;
	}
	return triangles;
}
*/
bitset<15>* MarchingCubeTable::getTriangles(bitset<15> input)
{
	int i = 0;
	//To every tetrohedron, find the triangles
	//bottom case:
	//case1: 0, 1, 14, 8
	constructTeTriangles(i, 0, 1, 14, 8, input);
	//case2: 1, 2, 14, 8
	constructTeTriangles(i, 1, 2, 14, 8, input);
	//case3: 2, 3, 14, 8
	constructTeTriangles(i, 2, 3, 14, 8, input);
	//case4: 3, 0, 14, 8
	constructTeTriangles(i, 3, 0, 14, 8, input);
	
	//top case:
	//case1: 4, 5, 13, 8
	constructTeTriangles(i, 4, 5, 13, 8, input);
	//case2: 5, 6, 13, 8
	constructTeTriangles(i, 5, 6, 13, 8, input);
	//case3: 6, 7, 13, 8
	constructTeTriangles(i, 6, 7, 13, 8, input);
   //case4: 7, 4, 13, 8
	constructTeTriangles(i, 7, 4, 13, 8, input);

	//left case:
	//case1: 0, 3, 12, 8
	constructTeTriangles(i, 0, 3, 12, 8, input);
	//case2: 3, 6, 12, 8
	constructTeTriangles(i, 3, 6, 12, 8, input);
	//case3: 6, 5, 12, 8
	constructTeTriangles(i, 6, 5, 12, 8, input);
	//case4: 5, 0, 12, 8
	constructTeTriangles(i, 5, 0, 12, 8, input);

	//right case:
	//case1: 1, 2, 10, 8
	constructTeTriangles(i, 1, 2, 10, 8, input);
	//case2: 2, 7, 10, 8
	constructTeTriangles(i, 2, 7, 10, 8, input);
	//case3: 7, 4, 10, 8
	constructTeTriangles(i, 7, 4, 10, 8, input);
	//case4: 4, 1, 10, 8
	constructTeTriangles(i, 4, 1, 10, 8, input);

	//front case:
	//case1: 0, 1, 9, 8
	constructTeTriangles(i, 0, 1, 9, 8, input);
	//case2: 1, 4, 9, 8
	constructTeTriangles(i, 1, 4, 9, 8, input);
	//case3: 4, 5, 9, 8
	constructTeTriangles(i, 4, 5, 9, 8, input);
	//case4: 5, 0, 9, 8
	constructTeTriangles(i, 5, 0, 9, 8, input);

	//back case:
	//case1: 2, 3, 11, 8
	constructTeTriangles(i, 2, 3, 11, 8, input);
	//case2: 3, 6, 11, 8
	constructTeTriangles(i, 3, 6, 11, 8, input);
	//case3: 6, 7, 11, 8
	constructTeTriangles(i, 6, 7, 11, 8, input);
	//case4: 7, 2, 11, 8
	constructTeTriangles(i, 7, 2, 11, 8, input);

	//Make the end of triangles to none
	setTrianglesEnd(i);

	//cout<<endl;

	return triangles;
}

//bitset<8> MarchingCubeTable::rot(bitset<8> input, int* rotate_array)
//{
//	bitset<8> result;
//	int index;
//	for(int i=0; i<8; i++)
//	{
//		index = rotate_array[i];
//		if(input.test(7-i))
//		{
//			result.set(7-index);
//		}
//	}
//	return result;
//}
//
//bitset<8> MarchingCubeTable::revert(bitset<8> input, int* rotate_array)
//{
//	bitset<8> result;
//	int index;
//	for(int i=0; i<8; i++)
//	{
//		index = rotate_array[i];
//		if(input.test(7-index))
//		{
//			result.set(7-i);
//		}
//	}
//	return result;
//}

void MarchingCubeTable::constructTeTriangles(int &i, 
											 int x1, int x2, int x3, int x4, bitset<15> input)
{
	int point_num = 0;
	bitset<15> bp[4];
	int b_x1 = 0, b_x2 = 0, b_x3 = 0, b_x4 = 0;

	//initialize b_x1, b_x2, b_x3, b_x4
	if(input.test(14-x1))
	{
		b_x1 = 1;
	}
	else
	{
		b_x1 = 0;
	}

	if(input.test(14-x2))
	{
		b_x2 = 1;
	}
	else
	{
		b_x2 = 0;
	}

	if(input.test(14-x3))
	{
		b_x3 = 1;
	}
	else
	{
		b_x3 = 0;
	}

	if(input.test(14-x4))
	{
		b_x4 = 1;
	}
	else
	{
		b_x4 = 0;
	}

	//Find the possible point
	//if there is no points, return immediately
	if((b_x1 == 1 && b_x2 == 1 && b_x3 == 1 && b_x4 == 1)
		|| (b_x1 == 0 && b_x2 == 0 && b_x3 == 0 && b_x4 == 0))
	{
		return;
	}
	//case0: x1, x2
	if(	b_x1 != b_x2)
	{
		bitset<15> temp;
		temp.set(14 - x1);
		temp.set(14 - x2);
		bp[point_num] = temp;
		point_num++;
	}

	//case1: x2, x3
	if(	b_x2 != b_x3)
	{
		bitset<15> temp;
		temp.set(14 - x2);
		temp.set(14 - x3);
		bp[point_num] = temp;
		point_num++;
	}

	//case2: x1, x3
	if(	b_x1 != b_x3)
	{
		bitset<15> temp;
		temp.set(14 - x1);
		temp.set(14 - x3);
		bp[point_num] = temp;
		point_num++;
	}

	//case3: x3, x4
	if(	b_x3 != b_x4)
	{
		bitset<15> temp;
		temp.set(14 - x3);
		temp.set(14 - x4);
		bp[point_num] = temp;
		point_num++;
	}

	//case4: x1, x4
	if(	b_x1 != b_x4)
	{
		bitset<15> temp;
		temp.set(14 - x1);
		temp.set(14 - x4);
		bp[point_num] = temp;
		point_num++;
	}

	//case5: x2, x4
	if(	b_x2 != b_x4)
	{
		bitset<15> temp;
		temp.set(14 - x2);
		temp.set(14 - x4);
		bp[point_num] = temp;
		point_num++;
	}

	//construct triangles
	//There are only two cases, three points and four points
	if(point_num == 0)
	{
		cout<<"error here!"<<endl;
		return;
	}
	else if(point_num == 3)
	{
		//three points, one triangle
		triangles[i++] = bp[0];
		triangles[i++] = bp[1];
		triangles[i++] = bp[2];
	}
	else if(point_num == 4)
	{
		//four points, two triangles, (0, 1, 2) and (0, 2, 3)
		triangles[i++] = bp[0];
		triangles[i++] = bp[1];
		triangles[i++] = bp[2];
		triangles[i++] = bp[0];
		triangles[i++] = bp[2];
		triangles[i++] = bp[3];
	}
}

void MarchingCubeTable::setTrianglesEnd(int i)
{
	bitset<15> temp;
	if(i < 144)
	{
		triangles[i] = temp;
	}
}